﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DevOnServer
{
    public class CMonster : CCreature
    {
        public CMonster(int id, CWorld world, CMoverProp prop, CVec3Df spawnPos)
            : base(id, world, prop)
        {
            HP = prop.HP;
            m_spawnPos = spawnPos;
        }

        public override CAttackResult attack(CCreature target, int attackMotion = 30)
        {
            m_attackResult.Damage = 0;
            m_attackResult.Flags = 0;

            if (!target.IsAlive)
                return m_attackResult;

            m_attackResult.Damage = CRandom.random(MoverProp.AtkMin, MoverProp.AtkMax);
            m_attackResult.Flags |= (CRandom.random(0, 5) == 0 ? (int)AttackFlags.Critical : 0);

            World.sendToLocalArea(this, CPacketCreator.attack(this, target, attackMotion));

            AttackTarget.damage(m_attackResult, this);

            return m_attackResult;
        }

        public override void kill(DeathType death, CCreature killer)
        {
            World.sendToLocalArea(this, CPacketCreator.moverDeath(this));

            m_removeTime = s_time + 5000;

            if (Respawner != null)
            {
                Respawner.removeObj(this);
                Respawner = null;
            }

            if (killer.Type == ObjType.Player)
            {
                CPlayerObject player = (CPlayerObject)killer;
                player.addMobExp(MoverProp.Exp);
                _dropItems(player);
            }
        }

        private void _dropItems(CPlayerObject player)
        {
            Position.Y = 0;
            World.createDropObject((int)DefineItem.II_GOLD_SEED1, Position, player);
        }

        public override void damage(CAttackResult result, CCreature attacker)
        {
            World.sendToLocalArea(this, CPacketCreator.damage(attacker, this, result.Damage, result.Flags));

            HP -= result.Damage;

            if (HP <= 0)
            {
                HP = 0;
                result.Kill = true;
                kill(DeathType.Player, attacker);
            }
            else if (AttackTarget == null && attacker.Type == ObjType.Player)
            {
                AttackTarget = (CPlayerObject)attacker;
                follow(attacker);
                m_nextAttackTime = s_time + 1000;
            }
        }

        public override void update()
        {
            if (m_removeTime != 0
                && s_time >= m_removeTime)
            {
                World.removeObject(this);
            }

            if (!IsAlive)
                return;

            _updatePosition();

            if (AttackTarget != null)
            {
                if (!Position.isInRange2D(AttackTarget.Position, 50.0f))
                {
                    AttackTarget = null;

                    follow(null);

                    walk(m_spawnPos);
                }
                else if (s_time >= m_nextAttackTime)
                {
                    attack(AttackTarget);

                    if (m_attackResult.Kill)
                    {
                        m_attackResult.Kill = false;
                        AttackTarget = null;
                        follow(null);
                    }

                    m_nextAttackTime = s_time + CRandom.random(MoverProp.AttackDelay, MoverProp.AttackDelay + 500);
                }
            }
            else if (s_time >= m_nextMoveTime)
            {
                CVec3Df newPos = new CVec3Df();
                newPos.X = CRandom.random(Position.X - 10, Position.X + 10);
                newPos.Z = CRandom.random(Position.Z - 10, Position.Z + 10);

                if (Respawner != null)
                {
                    if (newPos.X < Respawner.MinPos.X)
                        newPos.X = Respawner.MinPos.X;
                    else if (newPos.X > Respawner.MaxPos.X)
                        newPos.X = Respawner.MaxPos.X;

                    if (newPos.Z < Respawner.MinPos.Y)
                        newPos.Z = Respawner.MinPos.Y;
                    else if (newPos.Z > Respawner.MaxPos.Y)
                        newPos.Z = Respawner.MaxPos.Y;

                    newPos.Y = Respawner.HeightPos;

                    if (MoverProp.Flying)
                        newPos.Y = CRandom.random(newPos.Y - 10, newPos.Y + 10);
                }
                else
                {
                    if (newPos.X < m_spawnPos.X - 20.0f)
                        newPos.X = m_spawnPos.X - 20.0f;
                    else if (newPos.X > m_spawnPos.X + 20.0f)
                        newPos.X = m_spawnPos.X + 20.0f;

                    if (newPos.Z < m_spawnPos.Z - 20.0f)
                        newPos.Z = m_spawnPos.Z - 20.0f;
                    else if (newPos.Z > m_spawnPos.Z + 20.0f)
                        newPos.Z = m_spawnPos.Z + 20.0f;

                    newPos.Y = Position.Y;
                }

                walk(newPos);

                m_nextMoveTime = s_time + 6000 + CRandom.random(0, 6000);
            }

            if (Aggro && s_time >= m_nextAggressionTime)
            {
                if (AttackTarget == null)
                {
                    float range = MoverProp.AttackFirstRange * MoverProp.AttackFirstRange;

                    if (MoverProp.Flying)
                    {
                        foreach (CWorldObject obj in Field.Objects)
                        {
                            if (obj.Type == ObjType.Player)
                            {
                                if (obj.Position.isInRangeSq(Position, range))
                                {
                                    AttackTarget = (CPlayerObject)obj;
                                    range = (obj.Position - Position).LengthSq;
                                }
                            }
                        }
                    }
                    else
                    {
                        foreach (CWorldObject obj in Field.Objects)
                        {
                            if (obj.Type == ObjType.Player)
                            {
                                if (obj.Position.isInRangeSq2D(Position, range)
                                    && obj.Position.Y >= Position.Y - 30.0f
                                    && obj.Position.Y <= Position.Y + 30.0f)
                                {
                                    AttackTarget = (CPlayerObject)obj;
                                    range = (obj.Position - Position).LengthSq2D;
                                }
                            }
                        }
                    }

                    if (AttackTarget != null)
                    {
                        follow(AttackTarget);
                        m_nextAttackTime = s_time + MoverProp.AttackDelay;

                        World.sendToLocalArea(this, CPacketCreator.chat(ID, "!"));
                    }
                }

                m_nextAggressionTime = s_time + 500;
            }
        }

        public override ObjType Type
        {
            get
            {
                return ObjType.Monster;
            }
        }

        public bool Aggro;

        public CPlayerObject AttackTarget;

        private CVec3Df m_spawnPos;

        private int m_removeTime;

        private int m_nextAttackTime;

        private int m_nextMoveTime;

        private int m_nextAggressionTime;
    }
}